package tools;

import dao.Point;

import java.util.ArrayList;
import java.util.Arrays;

public class AIPlayer {

    private  int[][] chess=null;
    private int maxDepth;
    private boolean isFirstStep=true;
    private int tempx=0,tempy=0;
    public AIPlayer(int[][] chess,int depth)
    {
        this.chess=chess;
        this.maxDepth=depth;

    }
    //评估函数
    public long Evaluate(int flag)
    {
       long value = 0;
       for(int i=0;i<19;i++)
       {
           for (int j=0;j<19;j++)
           {
               if(chess[i][j]==flag) value+=JudgeChessFrom(flag,i,j);
           }
       }
       return value;
    }
    //判断棋形函数
    public long JudgeChessFrom(int flag,int x,int y)
    {
        int i,j,k1 = 0,k2=0;
        long value=0;
        int count=1;
        int status;
        //判断横向棋子个数
        if(y==0||chess[x][y-1]!=flag) {
            for (j = (y + 1 <= 18 ? y + 1 : 18); j <= ((y + 4 < 19) ? y + 4 : 18); j++) {
                if (chess[x][j] == flag) count++;
                else break;
            }
            if (j <= 18 && chess[x][j] == 0) k1 = 0;//k为0表示活棋
            else k1 = 1;

            for (j = (y - 1 >= 0 ? y - 1 : 0); j >= (y - 4 >= 0 ? y - 4 : 0); j--) {
                if (chess[x][j] == flag) count++;

                else break;
            }
            if (j >= 0 && chess[x][j] == 0) k2 = 0;
            else k2 = 1;

            //扫描完毕，判定棋子状态并获取分数
            if (count >= 5) return 100000000000000000l;
            if (k1 == 0 && k2 == 0) status = 0;// status 0 表示双活
            else if (k1 == 0 || k2 == 0) status = 1;// status 1表示单活
            else status = 2;// status 2表示死棋
            value += GetScore(count, status);//根据连在一起的棋子数量和状态获取评分

        }

        //判断纵向
        count=1;
        if(x==0||chess[x-1][y]!=flag)
        {
            for (i = (x + 1 <= 18 ? x + 1 : 18); i <= ((x + 4 < 19) ? x + 4 : 18); i++) {
                if (chess[i][y] == flag) count++;
                else break;
            }
            if (i <= 18 && chess[i][y] == 0) k1 = 0;//k为0表示活棋
            else k1 = 1;

            for (i = (x - 1 >= 0 ? x - 1 : 0); i >= (x - 4 >= 0 ? x - 4 : 0); i--) {
                if (chess[i][y] == flag) count++;
                else break;
            }
            if (i >= 0 && chess[i][y] == 0) k2 = 0;//k为0表示活棋
            else k2 = 1;

            //扫描完毕，判定棋子状态并获取分数
            if (count >= 5) return 100000000000000000l;
            if (k1 == 0 && k2 == 0) status = 0;
            else if (k1 == 0 || k2 == 0) status = 1;
            else status = 2;
            value += GetScore(count, status);
        }

        //判断斜向'/'
        count =1;
        if(x==0||y==18||chess[x-1][y+1]!=flag) {
            for (i = (x - 1 >= 0 ? x - 1 : 0), j = (y + 1 <= 18 ? y + 1 : 18); i >= (x - 4 >= 0 ? x - 4 : 0) && j <= ((y + 4 < 19) ? y + 4 : 18); i--, j++) {
                if (chess[i][j] == flag) count++;
                else break;
            }
            if (i >= 0 && j <= 18 && chess[i][j] == 0) k1 = 0;
            else k1 = 1;

            for (i = (x + 1 <= 18 ? x + 1 : 18), j = (y - 1 >= 0 ? y - 1 : 0); i <= ((x + 4 < 19) ? x + 4 : 18) && j >= (y - 4 >= 0 ? y - 4 : 0); i++, j--) {
                if (chess[i][j] == flag) count++;
                else break;

            }
            if (i <= 18 && j >= 0 && chess[i][j] == 0) k2 = 0;
            else k2 = 1;


            if (count >= 5) return 100000000000000000l;
            if (k1 == 0 && k2 == 0) status = 0;
            else if (k1 == 0 || k2 == 0) status = 1;
            else status = 2;
            value += GetScore(count, status);
        }
        //判断斜向'\'

        count =1;
        if(x==0||y==0||chess[x-1][y-1]!=flag) {
            for (i = (x - 1 >= 0 ? x - 1 : 0), j = (y - 1 >= 0 ? y - 1 : 0); i >= (x - 4 >= 0 ? x - 4 : 0) && j >= ((y - 4 >= 0) ? y - 4 : 0); i--, j--) {
                if (chess[i][j] == flag) count++;
                else break;
            }
            if (i >= 0 && j >= 0 && chess[i][j] == 0) k1 = 0;
            else k1 = 1;

            for (i = (x + 1 <= 18 ? x + 1 : 18), j = (y + 1 <= 18 ? y + 1 : 18); i <= ((x + 4 < 19) ? x + 4 : 18) && j <= ((y + 4 < 19) ? y + 4 : 18); i++, j++) {
                if (chess[i][j] == flag) count++;
                else break;
            }
            if (i <= 18 && j <= 18 && chess[i][j] == 0) k2 = 0;
            else k2 = 1;

            if (count >= 5) return 100000000000000000l;
            if (k1 == 0 && k2 == 0) status = 0;
            else if (k1 == 0 || k2 == 0) status = 1;
            else status = 2;
            value += GetScore(count, status);
        }

        return value;
    }

    //根据棋形打分
    public long GetScore(int count,int status)
    {

        if(count>=5) return 100000000000000000l;
        else if(count==4)
        {
            if(status==0)
            return 1000000000000l;
            else if(status==1)
                return 100000l;
            else return 80000l;
        }
        else if(count==3)
        {
            if(status==0)
            return 100000l;
            else
                if(status==1)
                    return 20l;
                else return 10l;

        }
        else if(count==2)
        {
            if(status==0)
            return 8l;
            else if(status==1)
                return 1l;
            else return 1l;
        }
        else if(count==1)
            return 0l;
        else return 0l;
    }
    //AI方判断下一步(极小值)
    public Point FindAIMove(int depth,long alpha,long beta)
    {
        Point p=null,BestPoint=null;
        Point BestDefense=null,BestAttack=null;
        long DefenseTempValue=100000000000000000l,AttackTempValue=100000000000000000l,HumanValue,AIValue;
        //固定判断套路，无脑判断肯定会下的棋，避免搜索开销
        if(depth==maxDepth) {
            for (int i = (tempx - 8 >= 0 ? tempx - 8 : 0); i <= (tempx + 8 <= 18 ? tempx + 8 : 18); i++)
                for (int j = (tempy - 8 >= 0 ? tempy - 8 : 0); j <= (tempy + 8 <= 18 ? tempy + 8 : 18); j++) {

                    if (chess[i][j] == 0) {
                        chess[i][j] = 2;
                        if (Evaluate(2) >= 100000000000000000l) {
                            chess[i][j] = 0;
                            return new Point(i, j, Evaluate(1) - Evaluate(2));
                        } else chess[i][j] = 0;

                        chess[i][j] = 1;
                        if (Evaluate(1) >= 100000000000000000l) {
                            chess[i][j] = 0;
                            return new Point(i, j,  Evaluate(1) - Evaluate(2));
                        } else chess[i][j] = 0;

                        chess[i][j] = 2;
                        AIValue=Evaluate(2);
                        HumanValue=Evaluate(1);
                        if(AIValue>= 1000000000000l) {
                            if(BestAttack==null||AttackTempValue>=5*HumanValue-Evaluate(2))
                            {
                                AttackTempValue=5*HumanValue-Evaluate(2);
                                BestAttack=new Point(i,j,5*HumanValue-Evaluate(2));
                            }
                        }
                        chess[i][j] = 0;

                        if(BestAttack==null) {
                            chess[i][j] = 1;
                            HumanValue = Evaluate(1);
                            if (HumanValue >= 1000000000000l) {
                                if (BestDefense==null||DefenseTempValue <=  HumanValue - Evaluate(2)) {
                                    System.out.println("defense");
                                    DefenseTempValue =   HumanValue - Evaluate(2);
                                    BestDefense = new Point(i, j,   HumanValue - Evaluate(2));
                                }
                            }
                            chess[i][j] = 0;
                        }



                    }
                }
           if(BestAttack!=null) return BestAttack;
            else if (BestDefense!=null) return  BestDefense;
        }
        //----------固定判断结束，开始搜索最佳位置-------------

        int i,j,x = 0,y=0;
        long MinValue=999999,value=0;
        for(i=(tempx-5>=0?tempx-5:0);i<=(tempx+5<=18?tempx+5:18);i++)
            for(j=(tempy-5>=0?tempy-5:0);j<=(tempy+5<=18?tempy+5:18);j++)
             {
                 if(alpha<=beta)//若给定的下限beta的值大于该节点上限值alpha，就返回刚才更新alpha值的点
                 {

                     return new Point(x,y,alpha);
                 }
                if(chess[i][j]==0)
                {
                    chess[i][j]=2;
                    if(depth>1)
                    {
                        p=FindHumanMove(depth-1,alpha,beta);
                        value=p.getValue();
                        if(value<alpha)//如果这个点的值比上限值大，则更新上限alpha
                        {
                            alpha=value;
                            x=i;
                            y=j;
                        }
                    }
                    else
                    {
                        value=Evaluate(1)-Evaluate(2);
                        if(value<alpha)
                        {
                            alpha=value;
                            x=i;
                            y=j;
                        }
                    }

                    if(value<MinValue||BestPoint==null)
                    {
                        MinValue=value;
                        BestPoint=new Point(i,j,MinValue);
                    }
                    chess[i][j]=0;
                }
             }
         return BestPoint;
    }
    //人类方判断下一步(极大值)
    public Point FindHumanMove(int depth,long alpha,long beta)
    {
        Point p=null,BestPoint=null;
        long MaxValue=-99999,value=0;
        int i,j,x = 0,y=0;
        for(i=(tempx-5>=0?tempx-5:0);i<=(tempx+5<=18?tempx+5:18);i++)
            for(j=(tempy-5>=0?tempy-5:0);j<=(tempy+5<=18?tempy+5:18);j++)
            {
                if(alpha<=beta)//若给定的上限alpha小于该节点的下限值beta，就返回刚才更新beta值的点
                {

                    return new Point(x,y,beta);
                }
                if(chess[i][j]==0)
                {
                    chess[i][j]=1;
                    if(depth>1)
                    {
                        p=FindAIMove(depth-1,alpha,beta);
                        value=p.getValue();
                        if(value>beta)//如果这个点的值比下限小
                        {
                            beta=value;
                            x=i;
                            y=j;
                        }
                    }
                    else
                    {
                        value=Evaluate(1)-Evaluate(2);
                        if(value>beta)
                        {
                            beta=value;
                            x=i;
                            y=j;
                        }
                    }

                    if(value>MaxValue||BestPoint==null)
                    {
                        MaxValue=value;
                        BestPoint=new Point(i,j,value);
                    }
                    chess[i][j]=0;
                }
            }
        return BestPoint;
    }



    public Point play()
    {

        Point p=null;
        if(this.isFirstStep)
        {
            for(int i=(tempx-4>=0?tempx-4:0);i<=(tempx+4<=18?tempx+4:18);i++)
                for(int j=(tempy-4>=0?tempy-4:0);j<=(tempy+4<=18?tempy+4:18);j++)
                {
                    if (chess[i][j]==1)
                    {
                        this.isFirstStep=false;
                        if(i+1<=18&&j+1<=18) return new Point(i+1,j+1,0);
                        else if(i-1>=0&&j-1>=0) return new Point(i-1,j-1,0);
                        else if(i+1<=18&&j-1>=0) return new Point(i+1,j-1,0);
                        else if(i-1>=0&&j+1<=18) return new Point(i-1,j+1,0);
                    }
                }
        }
        for(int i=0;i<=18;i++)
            for(int j=0;j<=18;j++)
            {
                if(chess[i][j]!=0) continue;
                chess[i][j]=2;
                long value=Evaluate(2);
                //System.out.println(i+" "+j+" "+value);
                if(value>=100000000000000000l)
                {
                    chess[i][j]=0;
                    return new Point(i,j,100000000000000000l);
                }
                chess[i][j]=0;
            }
         p=this.FindAIMove(maxDepth,9999999,-9999999);
        tempx=p.getX();
        tempy=p.getY();
        return p;
    }

    public boolean isFirstStep() {
        return isFirstStep;
    }

    public void setFirstStep(boolean firstStep) {
        isFirstStep = firstStep;
    }

    public int getTempx() {
        return tempx;
    }

    public void setTempx(int tempx) {
        this.tempx = tempx;
    }

    public int getTempy() {
        return tempy;
    }

    public void setTempy(int tempy) {
        this.tempy = tempy;
    }
}


